package models

import (
	"gorm.io/gorm"
	"gorm.io/gorm/clause"
)

type CRUD struct {
}

// Add 新增
// @db 数据库ORM对象
// @model 数据表模型（model:=models.User{}）
func (CRUD) Add(db *gorm.DB, model interface{}) (err error) {
	return db.Model(model).Create(model).Error
}

//// AddBatch 新增
//// @db 数据库ORM对象
//// @model 数据表模型（model:=models.User{}）
//func (CRUD) AddBatch(db *gorm.DB, model interface{}, list []interface{}) (err error) {
//	return db.Model(model).Create(list).Error
//}

// Mod 根据Model修改
// @db 数据库ORM对象
// @model 数据表模型（model:=models.User{}）
func (CRUD) Mod(db *gorm.DB, model interface{}) (err error) {
	return db.Model(model).Updates(model).Error
}

// ModByConds 条件修改
// @db 数据库ORM对象
// @model 数据表模型（model:=models.User{}）
// @conds 条件(id = ?)
// @params 条件值（对应条件的占位符）
func (CRUD) ModByConds(db *gorm.DB, model interface{}, conds string, params ...interface{}) (err error) {
	return db.Model(model).Where(conds, params...).Updates(model).Error
}

func (CRUD) ModMap(db *gorm.DB, data interface{}, updates map[string]interface{}, condition ...func(db *gorm.DB) *gorm.DB) error {
	return db.Model(data).
		Scopes(condition...).
		Updates(updates).
		Error
}

// FindOne 查询一条记录
// @db 数据库ORM对象
// @model 数据表模型（model:=models.User{}）
// @condition 条件
//		示例：cDto.MakeCondition(dto.StatTaskOrder{Id:111})
//		示例：cDto.MakeCondition(query.RegisterQuery{
//				UserName: c.UserName,
//				Email:    c.Email,
//				Mobile:   c.Mobile,
//			}
func (CRUD) FindOne(db *gorm.DB, model interface{}, condition ...func(db *gorm.DB) *gorm.DB) (err error) {
	//condition = func(db *gorm.DB) *gorm.DB {
	//	return db.Where("Register_name", "二楼机房")
	//}
	err = db.Model(model).
		Scopes(
			condition...,
		).First(model).Error
	return err
}

// FindOneByConds 查询一条记录
// @db 数据库ORM对象
// @model 数据表模型（model:=models.User{}）
// @condition 条件
//		示例：cDto.MakeCondition(dto.StatTaskOrder{Id:111})
//		示例：cDto.MakeCondition(query.RegisterQuery{
//				UserName: c.UserName,
//				Email:    c.Email,
//				Mobile:   c.Mobile,
//			}
func (CRUD) FindOneByConds(db *gorm.DB, model interface{}, conds string, params ...interface{}) (err error) {
	//condition = func(db *gorm.DB) *gorm.DB {
	//	return db.Where("Register_name", "二楼机房")
	//}
	return db.Model(model).Where(conds, params...).First(model).Error
}

// FindList 列表查询
// @db 数据库ORM对象
// @model 数据表模型（model:=models.User{}）
// @condition 条件
//		示例：cDto.MakeCondition(dto.StatTaskOrder{Id:111})
//		示例：cDto.MakeCondition(query.RegisterQuery{
//				UserName: c.UserName,
//				Email:    c.Email,
//				Mobile:   c.Mobile,
//			}
func (CRUD) FindList(db *gorm.DB, list interface{}, condition ...func(db *gorm.DB) *gorm.DB) (err error) {
	return db.Model(list).Scopes(
		condition...,
	).Find(list).Limit(-1).Offset(-1).Error
}

// FindPage 分页查询
// @db 数据库ORM对象
// @model 数据表模型（model:=models.User{}）
// @list 列表记录
// @count 行数
// @condition 条件
//		示例：cDto.MakeCondition(dto.StatTaskOrder{Id:111})
//		示例：cDto.MakeCondition(query.RegisterQuery{
//				UserName: c.UserName,
//				Email:    c.Email,
//				Mobile:   c.Mobile,
//			}
func (CRUD) FindPage(db *gorm.DB, list interface{}, count *int64, condition ...func(db *gorm.DB) *gorm.DB) (err error) {
	return db.Model(list).Scopes(
		condition...,
	).Find(list).Limit(-1).Offset(-1).Count(count).Error
}

// Del 条件删除
// @db 数据库ORM对象
// @model 数据表模型（model:=models.User{}）
// @conds 条件(id = ?)
// @params 条件值（对应条件的占位符）
func (CRUD) Del(db *gorm.DB, model interface{}, conds string, params ...interface{}) (err error) {
	return db.Model(model).Where(conds, params...).Delete(model).Error
	//if tx.RowsAffected == 0 {
	//	return errors.New("修改失败")
	//}
}
func (CRUD) DeleteByConds(db *gorm.DB, model interface{}, params ...interface{}) error {
	return db.Model(model).
		Delete(model, params...).
		Error
}

func (CRUD) Delete(db *gorm.DB, model interface{}, condition ...func(db *gorm.DB) *gorm.DB) error {
	return db.Model(model).Scopes(condition...).
		Delete(model).
		Error
}

// FindCountByConds 条件数量查询
// @db 数据库ORM对象
// @model 数据表模型（model:=models.User{}）
// @conds 条件(id = ?)
// @params 条件值（对应条件的占位符）
func (CRUD) FindCountByConds(db *gorm.DB, list interface{}, count *int64, conds string, params ...interface{}) error {
	return db.Model(list).Where(conds, params...).Find(list).Count(count).Error
}

// FindCount 数据查询
// @db 数据库ORM对象
// @model 数据表模型（model:=models.User{}）
// @list 列表记录
// @count 行数
// @condition 条件
//		示例：cDto.MakeCondition(dto.StatTaskOrder{Id:111})
//		示例：cDto.MakeCondition(query.RegisterQuery{
//				UserName: c.UserName,
//				Email:    c.Email,
//				Mobile:   c.Mobile,
//			}
func (CRUD) FindCount(db *gorm.DB, model interface{}, count *int64, condition ...func(db *gorm.DB) *gorm.DB) (err error) {
	return db.Model(model).Scopes(
		condition...,
	).Find(model).Count(count).Error
}

// FindListByConds 条件列表查询
// @db 数据库ORM对象
// @model 数据表模型（model:=models.User{}）
// @conds 条件(id = ?)
// @params 条件值（对应条件的占位符）
func (CRUD) FindListByConds(db *gorm.DB, model interface{}, conds string, params ...interface{}) (err error) {
	return db.Model(model).Where(conds, params...).Find(model).Error
}

func (CRUD) Upsert(db *gorm.DB, data interface{}, conflictColumns ...string) error {
	// 默认id主键字段冲突
	var columns = []string{"id"}
	if len(conflictColumns) > 0 {
		columns = conflictColumns
	}
	clauseColumns := make([]clause.Column, 0)
	for _, v := range columns {
		column := clause.Column{Name: v}
		clauseColumns = append(clauseColumns, column)
	}
	return db.Model(data).
		Clauses(clause.OnConflict{
			//Columns:   []clause.Column{{Name: "id"}},
			Columns:   clauseColumns,
			UpdateAll: true, // 更新除主键的所有字段
		}).
		Create(data).
		Error
}

func (CRUD) UpsertDoUpdate(db *gorm.DB, data interface{}, conflictColumns []string, doUpdates []string) error {
	// 默认id主键字段冲突
	var columns = []string{"id"}
	if len(conflictColumns) > 0 {
		columns = conflictColumns
	}
	clauseColumns := make([]clause.Column, 0)
	for _, v := range columns {
		column := clause.Column{Name: v}
		clauseColumns = append(clauseColumns, column)
	}
	conflict := clause.OnConflict{
		Columns: clauseColumns,
	}
	if len(doUpdates) == 0 {
		conflict.UpdateAll = true
	} else {
		// 更新指定列为新值
		conflict.DoUpdates = clause.AssignmentColumns(doUpdates)
	}
	return db.Model(data).
		Clauses(conflict).
		Create(data).
		Error
}
